﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Reflection;
using System.Diagnostics;
using System.Web;
using Infrastructure.Diagnostics.Configuration;

namespace Infrastructure.Diagnostics
{
    public static class Logger
    {
        public static int LogSeverity { get; private set; }

        static Logger()
        {
            LoggerSection loggerConfiguration =
            System.Configuration.ConfigurationManager.GetSection("LoggerConfiguration") as LoggerSection;

            LogSeverity = loggerConfiguration.Severity;
        }

        #region interface

        public static event EventHandler<LoggerEventArgs> Log;

        public static void Debug(string format, params object[] args)
        {
            AddEntry(Severity.Debug, string.Format(format, args));
        }

        public static void Info(string format, params object[] args)
        {
            AddEntry(Severity.Info, string.Format(format, args));
        }

        public static void Warning(string format, params object[] args)
        {
            AddEntry(Severity.Warning, string.Format(format, args));
        }

        public static void Error(string format, params object[] args)
        {
            AddEntry(Severity.Error, string.Format(format, args));
        }

        public static string ExceptionMessage(Exception e)
        {
            return string.Format(
                "Exception:\n" +
                "Type:    {0}\n" +
                "Data:    {1}\n" +
                "Source:  {2}\n" +
                "Message: {3}\n" +
                "StackTrace:\n{4}", e.GetType(), e.Data, e.Source, e.Message, e.StackTrace);
        }

        #endregion

        #region private methods

        private static void AddEntry(Severity severity, string message, string caller = null)
        {
            if (((int)severity & LogSeverity) != (int)severity) return;

            if (caller == null)
            {
                MethodBase mBase = GetCaller();
                caller = string.Format("{0}.{1}", mBase.DeclaringType, mBase.Name);
            }
            string[] callerArray = caller.Split('.');
            caller = string.Format("{0}.{1}", callerArray[callerArray.Length - 2], callerArray[callerArray.Length - 1]);

            string sessionId = (HttpContext.Current == null || HttpContext.Current.Session == null) ? "Application" : HttpContext.Current.Session.SessionID;

            EventHandler<LoggerEventArgs> l = Log;
            if (l != null)
                l(null, new LoggerEventArgs(severity, DateTime.Now, caller, sessionId, message));
        }

        private static MethodBase GetCaller()
        {
            var stackTrace = new StackTrace();
            int i = 0;
            while (stackTrace.GetFrame(i).GetMethod().DeclaringType != typeof(Logger)) ++i;
            while (stackTrace.GetFrame(i).GetMethod().DeclaringType == typeof(Logger)) ++i;
            return stackTrace.GetFrame(i).GetMethod();
        }

        #endregion
    }
}
